/****************************************************************************
 *
 *  ALi (Shanghai) Corporation, All Rights Reserved. 2002 Copyright (C)
 *
 *  File: nim_zl10036.c
 *
 *  Description: This file contains ZL10036 basic function in LLD.
 *
 *  History:
 *      Date        Author      Version  Comment
 *      ====        ======      =======  =======
 *  1.  2004.10.25  Liu Lan     0.1.000  Initial
 *  2.  2005.07.01  Zhu Jun    0.2.000  Add the Baseband Filter's bandwidth Control
 *  3.  08/31/2005	Zhu Jun	 0.3.000	Unify Tuner's configuration API Functions
 *
 ****************************************************************************/

#include <sys_config.h>


#include <retcode.h>
#include <types.h>

#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <bus/i2c/i2c.h>
#include <osal/osal_timer.h>

#include "nim_zl10036.h"

// local function
INT32 nim_zl10036_control_BW(struct QPSK_TUNER_CONFIG_EXT * stZL10036_ptr, UINT32 freq , UINT32 bs);

static unsigned char init_data0[] =
{
    0x04, 0x7E, 0xC0, 0x58, 0xF0, 0x02
};

static unsigned char init_data[] =
{
    0x04, 0x7E, 0xA1, 0x4A, 0xC0, 0x58, 0xD3, 0x40,
    0xE3, 0x5B, 0xF0, 0x28, 0xE3, 0xF9
};

struct QPSK_TUNER_CONFIG_EXT * stZL10036_dev_id[MAX_TUNER_SUPPORT_NUM] = {NULL};
static UINT32 stZL10036_tuner_cnt = 0;
/*****************************************************************************
* INT32 nim_zl10036_init(UINT32 para, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
*
* Tuner ZL10039 Initialization
*
* Arguments:
*  Parameter1: UINT32 para		: Input Parameter
*  Parameter2: struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config		: pointer for Tuner configuration structure
*
* Return Value: INT32			: Result
*****************************************************************************/
INT32 nim_zl10036_init(UINT32* tuner_id, struct QPSK_TUNER_CONFIG_EXT * ptrTuner_Config)
{
	INT32	result = 200;
	struct QPSK_TUNER_CONFIG_EXT * stZL10036_ptr = NULL;
	//soc_printf("enter nim_zl10036_init \n");
	/* check Tuner Configuration structure is available or not */
	if (ptrTuner_Config == NULL||stZL10036_tuner_cnt>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stZL10036_ptr = (struct QPSK_TUNER_CONFIG_EXT*)MALLOC(sizeof(struct QPSK_TUNER_CONFIG_EXT));
	if(!stZL10036_ptr)
		return ERR_FAILUE;
	MEMCPY(stZL10036_ptr, ptrTuner_Config, sizeof(struct QPSK_TUNER_CONFIG_EXT));
/*	soc_printf("%s: sizeof QPSK_TUNER_CONFIG_EXT = %d\n", __FUNCTION__, sizeof(struct QPSK_TUNER_CONFIG_EXT));
	soc_printf("Base Address: 0x%x\n",stZL10036_Config.cTuner_Base_Addr);
	soc_printf("Tuner Crystal: %dKHz\n",stZL10036_Config.wTuner_Crystal);
	soc_printf("Output Mode: %d (1 -- Signle End; 0 -- Differential)\n",stZL10036_Config.cTuner_Out_S_D_Sel);
*/
	*tuner_id = stZL10036_tuner_cnt;
	stZL10036_tuner_cnt++;

	/* Begin the Tuner Initialization Procedure */
	result = i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, init_data0, sizeof(init_data0));
	//soc_printf(" nim_zl10036_init result is 0x%x\n", result );

    	osal_delay(5000);

//    data[2] = 0x8A | (loop != 0);
	return i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, init_data, sizeof(init_data));
}


static unsigned char data[] =
{
    0x00, 0x00, 0xC0, 0x58, 0xF0, 0x70
};


INT32 nim_zl10036_control(UINT32 tuner_id, UINT32 freq ,UINT32 sym )
{
	unsigned int divider =0;
	UINT32 bs = 45000;
	struct QPSK_TUNER_CONFIG_EXT * stZL10036_ptr = NULL;
	if (tuner_id>=stZL10036_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
		return ERR_FAILUE;
	stZL10036_ptr = stZL10036_dev_id[tuner_id];
    	if (freq < 950)
		freq = 950;
    	else if (freq > 2160)
		freq = 2160;

	if (sym ==0)
		bs = 45000;
	else if (sym > 45000)
		bs = 45000;
	else
		bs = sym;

	//soc_printf("%s: Freq = %d, RS = %d\n", __FUNCTION__, freq, bs);
	// set Baseband Filter BandWidth
	nim_zl10036_control_BW(stZL10036_ptr, freq, bs);
	divider = (freq * 10000) / stZL10036_ptr->wTuner_Crystal;

    	data[0] = (unsigned char)((divider >> 8) & 0x7F);
    	data[1] = (unsigned char)divider;

	return i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, data, 2);
}

INT32 nim_zl10036_control_BW(struct QPSK_TUNER_CONFIG_EXT * stZL10036_ptr, UINT32 freq , UINT32 bs)
{
    unsigned char bData[4];
 
	unsigned char m_cBR, m_cBF, m_cReg7, m_cReg13;
	int	iFbw_3db, m_iFbw_3db;

	if (bs == 0)
		bs = 45000;

	if (bs<7100)	// 6.5Mbps is a threshould for low Symbol Rate
	{
		bData[0] = 0x83;//B1;//0x83;
		bData[1] = 0x4A;
	}
	else if (bs<16000)	// mid Symbol Rate
	{
		bData[0] = 0x83;//83;//0x83;
		bData[1] = 0x4A;
	}	else		// large Symbol Rate
	{
		bData[0] = 0x81;//A3;
		bData[1] = 0x4A;
	}
	i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, bData, 2);


	iFbw_3db = (int)(bs * 1.35  / 1.6 )+ 4000; //+m_iFoff;

	m_iFbw_3db = iFbw_3db;

	// 8Mhz <= Fbw_3dB <= 35MHz
	if (m_iFbw_3db < 8000)
		m_iFbw_3db = 8000;
	else if (m_iFbw_3db > 35000)
		m_iFbw_3db = 35000;

	//soc_printf("%s: m_iFbw_3db = %d, iFbw_3db = %d\n", __FUNCTION__, m_iFbw_3db, iFbw_3db);

	// calculate BR, BF


	if (m_iFbw_3db < 28820)
		m_cBR = (BYTE) (stZL10036_ptr->wTuner_Crystal/575);
	else
		m_cBR = (BYTE) (stZL10036_ptr->wTuner_Crystal * 63/m_iFbw_3db  / 1.257);

	float fTemp;
	fTemp = m_iFbw_3db * m_cBR * 1.257 / stZL10036_ptr->wTuner_Crystal -1;

	fTemp += 0.5;	//round to nearest INT value
	m_cBF = (BYTE) (fTemp);

	m_cReg7 = m_cBF<<1 ;
	m_cReg13 = m_cBR<<2 ;

	//soc_printf("%s: m_cBF = 0x%x, m_cBR = 0x%x\n", __FUNCTION__, m_cBF, m_cBR);
	bData[0] = 0xf0;
	 // BR
	bData[1] = m_cReg13;//	0x44;
	i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, bData, 2);

	bData[0] = 0xc8;
	// BF
	bData[1] = m_cReg7;//0x66;
	i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, bData, 2);
	bData[0] = 0xc0;
	i2c_write(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, bData, 1);


    return SUCCESS;
}

INT32 nim_zl10036_status(UINT32 tuner_id, UINT8 *lock)
{
    	long result;
    	unsigned char data;
	struct QPSK_TUNER_CONFIG_EXT * stZL10036_ptr = NULL;
	if (tuner_id>=stZL10036_tuner_cnt||tuner_id>=MAX_TUNER_SUPPORT_NUM)
	{
		*lock = 0;
		return ERR_FAILUE;
	}
	stZL10036_ptr = stZL10036_dev_id[tuner_id];
	result = i2c_read(stZL10036_ptr->i2c_type_id, stZL10036_ptr->cTuner_Base_Addr, &data, 1);
	//soc_printf(" nim_zl10036_status data is 0x%x\n", data );
    	*lock = (data >> 6) & 1;

    return result;
}

